package org.hales.util;

import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.github.pagehelper.PageInfo;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;

/**
 * 公共工具类
 * @author 陈建康
 */
public class HalesUtil {
    private static final Logger logger = LoggerFactory.getLogger(HalesUtil.class);

    /**
     * 手动分页查询
     * @param list 数据
     * @param pageNum 页码
     * @param pageSize 行数
     * @return {@link PageInfo }<{@link T }> 分页视图
     */
    public static <T> PageInfo<List<T>> getPageInfo(List<T> list, int pageNum, int pageSize){
        // 进行分页
        int startIndex = (pageNum - 1) * pageSize;
        int endIndex = Math.min(startIndex + pageSize, list.size());

        List<T> pageList = list.subList(startIndex, endIndex);

        // 构建分页信息
        PageInfo<List<T>> pageInfo = new PageInfo (pageList);
        pageInfo.setTotal(list.size());
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);
        pageInfo.setStartRow(startIndex + 1); // startRow 是从1开始的索引
        pageInfo.setEndRow(endIndex);
        pageInfo.setPages((int) Math.ceil((double) list.size() / pageSize)); // 总页数
        pageInfo.setPrePage((pageNum > 1) ? pageNum - 1 : 0); // 上一页
        pageInfo.setNextPage((endIndex < list.size()) ? pageNum + 1 : 0); // 下一页
        pageInfo.setIsFirstPage(pageNum == 1); // 是否是第一页
        pageInfo.setIsLastPage(endIndex >= list.size()); // 是否是最后一页
        return pageInfo;
    }


    /**
     * 下载文件并将其转换为 MultipartFile
     *
     * @param urlStr 文件 URL
     * @param fileName 文件名
     * @param contentType 文件内容类型
     * @return 转换后的 MultipartFile 对象
     * @throws IOException 如果下载或转换过程中发生 I/O 异常
     */
    public static MultipartFile downloadAndConvertToMultipartFile(String urlStr, String fileName, String contentType, String path) throws IOException {
        if (urlStr == null || urlStr.isEmpty()) {
            throw new IllegalArgumentException("URL 不能为空");
        }

        if (fileName == null || fileName.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        if (contentType == null || contentType.isEmpty()) {
            throw new IllegalArgumentException("内容类型不能为空");
        }

        logger.info("尝试从 URL 下载文件: " + urlStr);
        // 使用 hutool 下载文件到临时文件
        File tempFile = null;
        try {
            tempFile = HttpUtil.downloadFileFromUrl(urlStr,path);
            if (tempFile == null || !tempFile.exists()) {
                throw new IOException("下载失败，无法获取文件");
            }
        } catch (Exception e) {
            logger.error("下载失败，无法获取文件");
            throw e;
        }

        try {
            // 读取临时文件内容为字节数组
            byte[] fileBytes = org.apache.commons.io.FileUtils.readFileToByteArray(tempFile);

            // 创建 MockMultipartFile 对象
            return new MockMultipartFile(
                    "file", // 表单中文件字段的名称
                    fileName, // 文件名
                    contentType, // 文件内容类型
                    fileBytes // 文件字节数组
            );
        } finally {
            // 删除临时文件
            if (tempFile != null && tempFile.exists()) {
                tempFile.delete();
            }
        }
    }

    /**
     * 向指定URL发送POST请求，并返回响应结果
     *
     * @param url 请求的URL地址
     * @param headers 请求头，包含多个键值对
     * @param JSONStrBody 请求体内容，为JSON格式字符串
     * @return 返回响应结果，如果请求成功则为响应体内容，否则为null
     */
    public static String doPost(String url, Map<String,String> headers, String JSONStrBody){
        try (HttpResponse response = HttpUtil.createPost(url).body(JSONStrBody).addHeaders(headers).execute()){
            // 检查HTTP响应状态码是否为200，表示请求成功
            if(response.getStatus() == 200){
                logger.info("发送请求成功，返回:{}",response.body());
                return response.body();
            }else{
                // 如果状态码不是200，记录失败信息
                logger.info("发送请求失败:{}", response.body());
            }
        } catch (Exception e) {
            // 记录请求过程中出现的异常信息
            logger.info("接口异常信息：{}",e.getMessage());
        }
        // 如果请求失败或出现异常，返回null
        return null;
    }

    /**
     * 向指定URL发送POST请求，并返回响应结果
     *
     * @param url 请求的URL地址
     * @param headers 请求头，包含多个键值对
     * @param formData 请求体内容，为键值对形式
     * @return 返回响应结果，如果请求成功则为响应体内容，否则为null
     */
    public static String doPost(String url, Map<String, String> headers, Map<String, Object> formData) {
        try {
            // 创建POST请求
            try (HttpResponse response = HttpUtil.createPost(url)
                    // 添加请求头
                    .addHeaders(headers)
                    // 添加formData
                    .form(formData)
                    .execute()) {

                // 检查HTTP响应状态码是否为200，表示请求成功
                if (response.getStatus() == 200) {
                    logger.info("发送请求成功，返回:{}", response.body());
                    return response.body();
                } else {
                    // 如果状态码不是200，记录失败信息
                    logger.info("发送请求失败:{}", response.body());
                }
            }
        } catch (Exception e) {
            // 记录请求过程中出现的异常信息
            logger.info("接口异常信息：{}", e.getMessage());
        }
        // 如果请求失败或出现异常，返回null
        return null;
    }


    /**
     * 创建一个忽略SSL证书的Apache HttpClient实例
     * @return {@link CloseableHttpClient }
     */
    public static CloseableHttpClient createIgnoreSSLCertClientV1() {
        try {
            // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        public X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }
                        public void checkClientTrusted(X509Certificate[] certs, String authType) {
                        }
                        public void checkServerTrusted(X509Certificate[] certs, String authType) {
                        }
                    }
            };

            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            javax.net.ssl.SSLSocketFactory sf = sc.getSocketFactory();

            // Create HttpClient with custom SSLContext
            CloseableHttpClient httpClient = HttpClients.custom()
                    .setSSLContext(sc)
                    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    .build();

            return httpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建一个忽略SSL证书的Apache HttpClient实例
     * 此方法配置HttpClient以信任所有SSL证书，适用于开发或测试环境中的特殊需求
     * 注意：在生产环境中使用此方法会导致安全风险，因为它禁用了SSL证书的验证
     *
     * @return CloseableHttpClient实例，配置为忽略SSL证书
     * @throws Exception 如果SSLContext的初始化失败
     */
    private static CloseableHttpClient createIgnoreSSLCertClientV2() throws Exception {
        // 创建SSLContext，加载信任所有证书的材料
        SSLContext sslContext = SSLContextBuilder.create()
                .loadTrustMaterial((chain, authType) -> true) // 信任所有证书
                .build();

        // 创建SSLConnectionSocketFactory，使用上述SSLContext，并设置主机名验证为忽略
        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
                sslContext,
                NoopHostnameVerifier.INSTANCE // 忽略主机名验证
        );

        // 使用自定义的SSLConnectionSocketFactory构建并返回HttpClient实例
        return HttpClients.custom()
                .setSSLSocketFactory(sslSocketFactory)
                .build();
    }

    /**
     * 将经纬度转换为度分秒格式
     *
     * @param du 116.41884740.0897315
     * @return 116°25'7.85"       40°5'23.03"
     */
    public static String latLng2Dfm(double du) {
        int du1 = (int) du;
        double tp = (du - du1) * 60;
        int fen = (int) tp;
        String miao = String.format("%.2f", Math.abs(((tp - fen) * 60)));
        return du1 + "°" + Math.abs(fen) + "'" + miao + "\"";
    }
}
